package com.lemon.rpcframe.provider;

import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.log4j.Logger;

import com.alibaba.fastjson.JSONObject;
import com.lemon.rpcframe.commons.DTaskProvider;
import com.lemon.rpcframe.commons.InjectorHolder;
import com.lemon.rpcframe.contract.RemoteTaskService;
import com.lemon.rpcframe.core.BeanConverter;
import com.lemon.rpcframe.dao.entity.TaskDefineBean;
import com.lemon.rpcframe.dao.entity.TaskExecutableBean;
import com.lemon.rpcframe.dao.entity.TaskLogBean;
import com.lemon.rpcframe.util.CronExpressionUtils;
import com.lemon.rpcframe.util.GenericsUtils;
import com.lemon.rpcframe.util.StringUtils;

public class RemoteTaskServiceImpl implements RemoteTaskService {

    private static final Logger logger = Logger.getLogger(RemoteTaskServiceImpl.class);
    private static final ConcurrentHashMap<String, ReentrantLock> taskpullMap = GenericsUtils.newConcurrentHashMap();

    @Override
    public long addNodeGroup(String nodeType, String nodeGroup) throws Exception {
        long id = InjectorHolder.getInstance(DTaskProvider.class).addNodeGroup(nodeType, nodeGroup);
        return id;
    }

    @Override
    public void finishTask(long jobId) throws Exception {
        try {
            InjectorHolder.getInstance(DTaskProvider.class).deleteExecutingTaskByJobID(jobId);
            TaskDefineBean define = InjectorHolder.getInstance(DTaskProvider.class).loadTaskDefineByJobID(jobId);
            if (define == null) {
                logger.info(String.format("define is null ,jobid=%s  ", jobId));
            }
            if (isScheduler(define)) {
                Date nextTrigger = CronExpressionUtils.getNextTriggerTime(define.getCronExpression());
                if (nextTrigger == null) {
                    logger.info(String.format("cron is invalid ,jobid=%s  ", jobId));
                } else {
                    TaskExecutableBean executable = BeanConverter.defineToExecutable(define);
                    executable.setTriggerDate(nextTrigger);
                    InjectorHolder.getInstance(DTaskProvider.class).addExecutableTask(executable);
                }
            }
        } catch (Exception e) {
            logger.error(e);
        }
    }

    @Override
    public TaskExecutableBean taskPull(String taskGroup, String taskIdentity) throws Exception {
        ReentrantLock lock = taskpullMap.get(taskGroup);
        if (lock == null) {
            lock = new ReentrantLock();
            taskpullMap.put(taskGroup, lock);
        }
        long jobid = 0l;
        try {
            lock.tryLock(2000, TimeUnit.MILLISECONDS);
            TaskExecutableBean task = InjectorHolder.getInstance(DTaskProvider.class).takeExecutaleTask(taskGroup, taskIdentity);
            if (task != null) {
                //                jobid = task.getJobId();
                //                TaskExecutingBean taskExecuting = executableToExecutng(task);
                //                InjectorHolder.getInstance(DTaskProvider.class).addExecutingTask(taskExecuting);
                //                InjectorHolder.getInstance(DTaskProvider.class).deleteExecutableTask(jobid, taskGroup);
                logger.info(JSONObject.toJSONString(task));
                return task;
            }
        } catch (Exception e) {
            logger.error(e);
            if (jobid > 0) {
                InjectorHolder.getInstance(DTaskProvider.class).resetExecutableTask(jobid, taskGroup);
            }
        } finally {
            lock.unlock();
        }
        return null;
    }

    /**
     * 待执行  转化为    正在执行
     * @param task
     * @return
     */

    private boolean isScheduler(TaskDefineBean define) {
        return !StringUtils.isNullOrEmpty(define.getCronExpression());
    }

    @Override
    public void addTaskLog(TaskLogBean bean) throws Exception {
        if (bean.getEndTime() == null) {
            bean.setEndTime(new Date());
        }
        InjectorHolder.getInstance(DTaskProvider.class).addTaskLog(bean);
    }

}
